#include "createconnection.h"
#include <QFormLayout>
#include <QGroupBox>
#include <QMessageBox>
#include <QVBoxLayout>


Listen::Listen(QWidget *parent)
        : QWidget(parent)
{
    this->tcpServer = new QTcpServer();
    QObject::connect(this->tcpServer, SIGNAL(newConnection()), this, SLOT(incomingConnection()));

    this->isListening = false;

    listenPort = new QSpinBox();
        listenPort->setMinimum(1024);
        listenPort->setMaximum(65535);
        listenPort->setValue(1337);
    submitButton = new QPushButton(tr("Listen!"));

    QObject::connect(this->submitButton, SIGNAL(pressed()), this, SLOT(onSubmit()));

    QFormLayout *listenForm = new QFormLayout();
    listenForm->addRow(tr("Port:"), this->listenPort);
    listenForm->addRow("", this->submitButton);
    this->setLayout(listenForm);
}

void Listen::onSubmit()
{
    if (!isListening) //let's start listening
    {
        Q_ASSERT(this->listenPort->value() != 0);

        if (!this->tcpServer->listen(QHostAddress::Any, this->listenPort->value()))
        {
            //TODO: Give error..
            // i recommend some kind of qt abort function
            return;
        }

        this->listenPort->setEnabled(false);
        this->submitButton->setText("STOP");

        this->isListening = true;;

        emit this->startedListening(this->listenPort->value());
    }
    else //close connection..
    {
        this->tcpServer->close();
        //enable the ui again
        this->listenPort->setEnabled(true);
        this->submitButton->setText(tr("Listen!"));

        this->isListening = false;
        emit this->stoppedListening();
    }
}

void Listen::incomingConnection()
{
    qDebug("Incoming Connection (listen)");
    //we have no use for it, so let's pass the baby on
    emit this->newConnection(this->tcpServer->nextPendingConnection());
}


Send::Send(QWidget *parent)
        : QWidget(parent)
{
    this->tcpSocket = NULL;

    this->sendDestination = new QLineEdit("127.0.0.1");
    this->sendPort = new QSpinBox();
        //this-sendPort->setMinimum(PROPER ACCEPTABLE MIN);
        this->sendPort->setMaximum(64999);
        this->sendPort->setValue(1337);
    this->sendConnect = new QPushButton(tr("Connect!"));

    QObject::connect(sendConnect, SIGNAL(clicked()), this, SLOT(onSubmit()));

    //now let's put it in a form
    QFormLayout *sendForm = new QFormLayout();
    sendForm->addRow(tr("Destination"), this->sendDestination);
    sendForm->addRow(tr("Port:"), this->sendPort);
    sendForm->addRow("", this->sendConnect);

    this->setLayout(sendForm);


}

void Send::onSubmit()
{
    if(this->tcpSocket == NULL)
    {
        this->tcpSocket = new QTcpSocket();

        QHostAddress target(this->sendDestination->text());
        this->tcpSocket->connectToHost(target, this->sendPort->value());
        QObject::connect(this->tcpSocket, SIGNAL(connected()), this, SLOT(connectionReady()));
        QObject::connect(this->tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                         this, SLOT(errored(QAbstractSocket::SocketError)));

        this->lockGui();

        emit startedSending(target, this->sendPort->value());
    }
    else
    {
        //let's cancel it
        this->abortSending();
    }
}


void Send::connectionReady()
{
    qDebug("Connection Reader (Sender)");

    //let's get rid of our old signals
    this->tcpSocket->disconnect();

    //now give away our socket
    emit newConnection(this->tcpSocket);

    //and clear it locally
    this->tcpSocket = NULL;

    //and let it be known
    this->unlockGui();
    emit stoppedSending();
}

void Send::errored(QAbstractSocket::SocketError socketError)
{
    // Funtion jacked from Qt Software ;D
     switch (socketError)
     {
     case QAbstractSocket::RemoteHostClosedError:
         break;
     case QAbstractSocket::HostNotFoundError:
         QMessageBox::information(this, tr("Debug"),
                                  tr("The host was not found. Please check the "
                                     "host name and port settings."));
         break;
     case QAbstractSocket::ConnectionRefusedError:
         QMessageBox::information(this, tr("Debug"),
                                  tr("The connection was actively refused (check firewalls, ip, router etc.)"));
         break;
     default:
         QMessageBox::information(this, tr("Debug"),
                                  tr("The following error occurred: %1.")
                                  .arg(tcpSocket->errorString()));
     }


     this->abortSending();
}


void Send::abortSending()
{
    Q_ASSERT(this->tcpSocket != NULL);

    this->tcpSocket->abort();
    delete this->tcpSocket;
    this->tcpSocket = NULL;

    this->unlockGui();
    emit stoppedSending();

}

void Send::lockGui()
{
    this->sendDestination->setEnabled(false);
    this->sendPort->setEnabled(false);
    this->sendConnect->setText(tr("STOP"));
}

void Send::unlockGui()
{
    this->sendDestination->setEnabled(true);
    this->sendPort->setEnabled(true);
    this->sendConnect->setText(tr("connect"));
}



CreateConnection::CreateConnection(QWidget *parent)
        : QWidget(parent)
{
    connectionTitle = new QLabel(tr("Establish a Connection"));
        //connectionTitle->setFont(SOMETHING_NICE_AND_BIG);

    QGroupBox *sendGroup = new QGroupBox(tr("Sender"));
    QVBoxLayout *lay = new QVBoxLayout();
    send = new Send();
    lay->addWidget(send);
    sendGroup->setLayout(lay);

    QGroupBox *listenGroup = new QGroupBox(tr("Listener"));
    QVBoxLayout *lay2 = new QVBoxLayout();
    listen = new Listen(listenGroup);
    lay2->addWidget(listen);
    listenGroup->setLayout(lay2);

    //Now time to create the layout..
    QGridLayout *layout = new QGridLayout();

    layout->addWidget(this->connectionTitle, 0, 0, 1, 2);
    layout->addWidget(sendGroup, 1, 0);
    layout->addWidget(listenGroup, 1, 1);

    this->setLayout(layout);

    //now we're essentially going to escalate
    //signals from listen and send

    QObject::connect(listen, SIGNAL(newConnection(QTcpSocket*)), this, SIGNAL(newConnection(QTcpSocket*)));
    QObject::connect(send, SIGNAL(newConnection(QTcpSocket*)), this, SIGNAL(newConnection(QTcpSocket*)));

    QObject::connect(this, SIGNAL(newConnection(QTcpSocket*)), this, SLOT(connectedMsg(QTcpSocket*)));

    QObject::connect(listen, SIGNAL(startedListening(int)), this, SLOT(startedListening(int)));
    QObject::connect(listen, SIGNAL(stoppedListening()), this, SLOT(stoppedListening()));

    QObject::connect(send, SIGNAL(startedSending(QHostAddress,int)), this, SLOT(startedSending(QHostAddress,int)));
    QObject::connect(send, SIGNAL(stoppedSending()), this, SLOT(stoppedSending()));
}

void CreateConnection::connectedMsg(QTcpSocket *tcpSocket)
{
    emit this->newStatusBarMsg(tr("We have a new connection from %1").arg(tcpSocket->peerAddress().toString()));
}

void CreateConnection::startedListening(int port)
{
    emit this->newStatusBarMsg(tr("Started listening on port %1").arg(port));
}

void CreateConnection::stoppedListening()
{
    emit this->newStatusBarMsg(tr("Stopped listening"));
}

void CreateConnection::startedSending(QHostAddress dest, int port)
{
    emit this->newStatusBarMsg(tr("Trying to connect to %1 on port %2 ").arg(dest.toString()).arg(port));
}

void CreateConnection::stoppedSending()
{
    emit this->newStatusBarMsg(tr("End of trying to connect"));
}
